﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace cstdx.Internal;


public static class TimeUtils
{
	private const int __tm_h_width = 1000000;
	private const int __tm_m_width = 10000;
	private const int __tm_t_width = 1000;

	/// <summary>
	/// 格式化时间字符串（与timeFromStr功能相同）
	/// </summary>
	public static string FormatTime0(string timeStamp)
	{
		int length = timeStamp.Length;
		long t1 = long.Parse(timeStamp.Substring(0, length - 6));
		StringBuilder tm = new StringBuilder();
		tm.AppendFormat("{0:D2}:", t1);

		string tmp = timeStamp.Substring(length - 6, 2);
		long n = long.Parse(tmp);

		if (n < 60)
		{
			tm.AppendFormat("{0:D2}:", tmp);
			tmp = timeStamp.Substring(length - 4);
			double f = double.Parse(tmp);
			tm.AppendFormat("{0:F3}", (f * 60.0) / 10000.00);
		}
		else
		{
			tmp = timeStamp.Substring(length - 6);
			double f = double.Parse(tmp);
			tm.AppendFormat("{0:D2}:", (long)(f * 60.0) / 1000000);
			long nVal = (long)f;
			tm.AppendFormat("{0:F3}", (double)((nVal * 60) % 1000000) * 60 / 1000000.0);
		}

		return tm.ToString();
	}

	/// <summary>
	/// 从字符串格式化时间
	/// </summary>
	public static string TimeFromStr(string timeStamp)
	{
		// 与FormatTime0逻辑完全一致，此处省略重复实现（实际项目中可合并）
		return FormatTime0(timeStamp);
	}

	/// <summary>
	/// 从整数时间戳格式化时间
	/// </summary>
	public static string TimeFromInt(int stamp)
	{
		int h = stamp / __tm_h_width;
		int tmp1 = stamp % __tm_h_width;
		int m1 = tmp1 / __tm_m_width;
		int tmp2 = tmp1 % __tm_m_width;

		int m = 0;
		int s = 0;
		int t = 0;
		double st = 0.00;

		if (m1 < 60)
		{
			m = m1;
			int tmp3 = tmp2 * 60;
			s = tmp3 / __tm_m_width;
			t = tmp3 % __tm_m_width;
			t /= 10;
			st = (double)tmp3 / __tm_m_width;
		}
		else
		{
			h += 1;
			int tmp3 = tmp1;
			m = tmp3 / __tm_h_width;
			int tmp4 = (tmp3 % __tm_h_width) * 60;
			s = tmp4 / __tm_h_width;
			t = tmp4 % __tm_h_width;
			t /= __tm_t_width;
			st = (double)tmp4 / __tm_h_width;
		}

		return string.Format("{0:D2}:{1:D2}:{2:F3}", h, m, st);
	}

	/// <summary>
	/// 从无符号整数获取日期时间
	/// </summary>
	public static (int year, int month, int day, int hour, int minute) GetDatetimeFromUint32(int category, uint zipday, ushort tminutes)
	{
		int hour = 15;
		int year = 0, month = 0, day = 0, minute = 0;

		if (category < 4 || category == 7 || category == 8)
		{
			year = (int)((zipday >> 11) + 2004);
			month = (int)((zipday % 2048) / 100);
			day = (int)((zipday % 2048) % 100);
			hour = (int)(tminutes / 60);
			minute = (int)(tminutes % 60);
		}
		else
		{
			year = (int)(zipday / 10000);
			month = (int)((zipday % 10000) / 100);
			day = (int)(zipday % 100);
		}

		return (year, month, day, hour, minute);
	}

	/// <summary>
	/// 获取当前时间（基于最后时间和周期类型）
	/// </summary>
	public static (int year, int month, int day, int hour, int minute) GetDatetimeNow(int category, string lasttime)
	{
		DateTime utime = DateTime.Parse(lasttime);

		// 根据周期类型添加相应时间间隔
		switch (category)
		{
			case KLINE_TYPE_5MIN:
				utime = utime.AddMinutes(5);
				break;
			case KLINE_TYPE_15MIN:
				utime = utime.AddMinutes(15);
				break;
			case KLINE_TYPE_30MIN:
				utime = utime.AddMinutes(30);
				break;
			case KLINE_TYPE_1HOUR:
				utime = utime.AddHours(1);
				break;
			case KLINE_TYPE_DAILY:
				utime = utime.AddDays(1);
				break;
			case KLINE_TYPE_WEEKLY:
				utime = utime.AddDays(7);
				break;
			case KLINE_TYPE_MONTHLY:
				utime = utime.AddMonths(1);
				break;
			case KLINE_TYPE_EXHQ_1MIN:
				utime = utime.AddMinutes(1);
				break;
			case KLINE_TYPE_1MIN:
				utime = utime.AddMinutes(1);
				break;
			case KLINE_TYPE_RI_K:
				utime = utime.AddDays(1);
				break;
			case KLINE_TYPE_3MONTH:
				utime = utime.AddMonths(3);
				break;
			case KLINE_TYPE_YEARLY:
				utime = utime.AddYears(1);
				break;
		}

		int hour = 0, minute = 0;
		if (category < 4 || category == 7 || category == 8)
		{
			if ((utime.Hour >= 15 && utime.Minute > 0) || utime.Hour > 15)
			{
				utime = utime.AddDays(1);
				utime = utime.AddMinutes(30);
				hour = (utime.Hour + 18) % 24;
			}
			else
			{
				hour = utime.Hour;
			}
			minute = utime.Minute;
		}
		else
		{
			if (utime.Ticks > DateTime.Now.Ticks)
			{
				utime = DateTime.Now;
			}
			hour = utime.Hour;
			minute = utime.Minute;
			if (utime.Hour > 15)
			{
				hour = 15;
				minute = 0;
			}
		}

		return (utime.Year, utime.Month, utime.Day, hour, minute);
	}

	/// <summary>
	/// 从字节数组获取时间（小时和分钟）
	/// </summary>
	public static (ushort h, ushort m) GetTime(byte[] b, ref int pos)
	{
		ushort sec = BitConverter.ToUInt16(b, pos);
		// 确保小端字节序（如果系统是大端需要转换，这里默认小端）
		if (!BitConverter.IsLittleEndian)
			sec = ReverseBytes(sec);

		ushort h = (ushort)(sec / 60);
		ushort m = (ushort)(sec % 60);
		pos += 2;

		return (h, m);
	}

	/// <summary>
	/// 从字节数组获取日期时间
	/// </summary>
	public static (int year, int month, int day, int hour, int minute) GetDatetime(int category, byte[] b, ref int pos)
	{
		int hour = 15;
		int year = 0, month = 0, day = 0, minute = 0;

		if (category < 4 || category == 7 || category == 8)
		{
			ushort zipday = BitConverter.ToUInt16(b, pos);
			if (!BitConverter.IsLittleEndian)
				zipday = ReverseBytes(zipday);
			pos += 2;

			ushort tminutes = BitConverter.ToUInt16(b, pos);
			if (!BitConverter.IsLittleEndian)
				tminutes = ReverseBytes(tminutes);
			pos += 2;

			year = (int)((zipday >> 11) + 2004);
			month = (int)((zipday % 2048) / 100);
			day = (int)((zipday % 2048) % 100);
			hour = (int)(tminutes / 60);
			minute = (int)(tminutes % 60);
		}
		else
		{
			uint zipday = BitConverter.ToUInt32(b, pos);
			if (!BitConverter.IsLittleEndian)
				zipday = ReverseBytes(zipday);
			pos += 4;

			year = (int)(zipday / 10000);
			month = (int)((zipday % 10000) / 100);
			day = (int)(zipday % 100);
		}

		return (year, month, day, hour, minute);
	}

	// 辅助方法：反转ushort字节（用于大端系统转换）
	private static ushort ReverseBytes(ushort value)
	{
		return (ushort)(((value & 0xFFU) << 8) | ((value & 0xFF00U) >> 8));
	}

	// 辅助方法：反转uint字节（用于大端系统转换）
	private static uint ReverseBytes(uint value)
	{
		return ((value & 0x000000FFU) << 24) |
			   ((value & 0x0000FF00U) << 8) |
			   ((value & 0x00FF0000U) >> 8) |
			   ((value & 0xFF000000U) >> 24);
	}

	// 周期类型常量（需与proto中的定义保持一致）
	public const int KLINE_TYPE_5MIN = 0;
	public const int KLINE_TYPE_15MIN = 1;
	public const int KLINE_TYPE_30MIN = 2;
	public const int KLINE_TYPE_1HOUR = 3;
	public const int KLINE_TYPE_DAILY = 4;
	public const int KLINE_TYPE_WEEKLY = 5;
	public const int KLINE_TYPE_MONTHLY = 6;
	public const int KLINE_TYPE_EXHQ_1MIN = 7;
	public const int KLINE_TYPE_1MIN = 8;
	public const int KLINE_TYPE_RI_K = 9;
	public const int KLINE_TYPE_3MONTH = 10;
	public const int KLINE_TYPE_YEARLY = 11;
}

